using System;
using SharpObjects.Cryptography.Asymmetric;
using SharpObjects.Cryptography.DigitalSignature;
using SharpObjects.Cryptography.Symmetric;

namespace SharpObjects.Cryptography
{
	// key general_key.crk "myinitvector1234" "mycryptographykey123456789012345"
	//

	class Generator
	{
		[STAThread]
		static void Main(string[] args)
		{
			if(args.Length == 0)
			{
				Usage();
				return;
			}
			else
			{
				if(args[0].ToLower() == "-h" || args[0].ToLower().IndexOf("help") >= 0)
				{
					Usage();
					return;
				}
			}

			try
			{

				switch(args[0].ToLower())
				{
					case "key": CreateKey(args); break;
					case "encrypt": Encrypt(args); break;
					case "decrypt": Decrypt(args); break;
					case "sign": Sign(args); break;
					case "verify": Verify(args); break;
					default: 
						Console.WriteLine("Invalid command.");
						Usage();
						break;
				}
			}
			catch(Exception ex)
			{
				Console.WriteLine(ex.Message);
			}
		}

		protected static void Usage()
		{
			Console.WriteLine("\nSharpCryptoGen.exe <command> [<args>]\n");
			Console.WriteLine("    Commands:");
			Console.WriteLine("        key - create key file, \n            arguments: <file name base> <algorithm: rij, rsa, dsa> \n                [symmetric only: <init vector (16 bytes)> <key (32 bytes)>]");
			Console.WriteLine("        encrypt - encrypt and print base 64 text, \n            argumens: <key file> <algorithm: rij, rsa> <plain text> \n                (text with spaces can be put in quotes)");
			Console.WriteLine("        decrypt - decrypt and print plain text,\n            argumens: <key file> <algorithm: rij, rsa> <base 64 text> \n                (text with spaces can be put in quotes)");
			Console.WriteLine("        sign - create hash, sign and print base 64 signed hash, \n            argumens: <key file> <algorithm: dsa> <plain text> \n                (text with spaces can be put in quotes)");
			Console.WriteLine("        verify - create hash, sign and compare with provided signed hash,\n            argumens: <key file> <algorithm: dsa> <plain text> \n                       <base 64 signature>\n                (text with spaces can be put in quotes)");
		}

		protected static void CreateKey(string [] args)
		{
			if(args.Length == 0)
			{
				Usage();
				return;
			}
			else if(args.Length == 1)
			{
				Console.WriteLine("Missing file name and algorithm name.");
				Usage();
				return;
			}
			if(args.Length == 2)
			{
				Console.WriteLine("Missing algorithm name");
				Usage();
				return;
			}
			else if( args.Length == 3)
			{
				if(args[2].ToLower() == "rij")
				{
					RijndaelProvider provider = new RijndaelProvider();
					KeyFile file = new KeyFile(args[1] + ".key", provider);
					file.Save();
				}
				else if(args[2].ToLower() == "rsa")
				{
					RsaProvider provider = new RsaProvider();

					provider.HidePrivateKey = false;
					KeyFile file = new KeyFile(args[1] + ".keys", provider);
					file.Save();
					
					provider.HidePrivateKey = true;
					file = new KeyFile(args[1] + ".pubkey", provider);
					file.Save();
				}
				else if(args[2].ToLower() == "dsa")
				{
					DsaProvider provider = new DsaProvider();

					provider.HidePrivateKey = false;
					KeyFile file = new KeyFile(args[1] + ".keys", provider);
					file.Save();
					
					provider.HidePrivateKey = true;
					file = new KeyFile(args[1] + ".pubkey", provider);
					file.Save();
				}

			}
			else if(args.Length == 5)
			{
				if(args[2].ToLower() == "rij")
				{
					RijndaelProvider provider = new RijndaelProvider(args[3], args[4]);
					KeyFile file = new KeyFile(args[1] + ".key", provider);
					file.Save();
				}
				else
				{
					Console.WriteLine("Specified provider cannot have init vector and key arguments");
					Usage();
					return;
				}
			}
			else
			{
				Console.WriteLine("Invalid syntax.");
				Usage();
				return;
			}
		}

		protected static void Encrypt(string [] args)
		{
			if(args.Length == 4)
			{
				ICryptoProvider provider;

				if(args[2].ToLower() == "rij")
				{
					provider = new RijndaelProvider();
				}
				else
				{
					provider = new RsaProvider();
				}

				KeyFile keyfile = new KeyFile(args[1], provider);
				keyfile.Load();

				Cryptographer crypt = new Cryptographer(provider);
				string sEncrypted = crypt.EncryptToBase64Text(args[3]);
				Console.WriteLine(sEncrypted);
			}
			else
			{
				Console.WriteLine("Invalid syntax.");
				Usage();
				return;
			}
		}

		protected static void Decrypt(string [] args)
		{
			if(args.Length == 4)
			{
				ICryptoProvider provider;
				
				if(args[2].ToLower() == "rij")
				{
					provider = new RijndaelProvider();
				}
				else
				{	
					provider = new RsaProvider();
				}

				KeyFile keyfile = new KeyFile(args[1], provider);
				keyfile.Load();
				Cryptographer crypt = new Cryptographer(provider);
				string sDecrypted = crypt.DecryptToUtf8Text(args[3]);
				Console.WriteLine(sDecrypted);
			}
			else
			{
				Console.WriteLine("Invalid syntax.");
				Usage();
				return;
			}
		}

		protected static void Sign(string [] args)
		{
			if(args.Length == 4)
			{
				IDigitalSignatureProvider provider = new DsaProvider();
				KeyFile keyfile = new KeyFile(args[1], (ICryptoProvider)provider);
				keyfile.Load();

				NotaryPublic notary = new NotaryPublic(provider);
				string sSignature = notary.GetBase64Signature(args[3]);
				Console.WriteLine(sSignature);
			}
			else
			{
				Console.WriteLine("Invalid syntax.");
				Usage();
				return;
			}
		}

		protected static void Verify(string [] args)
		{
			if(args.Length == 5)
			{
				IDigitalSignatureProvider provider = new DsaProvider();
				KeyFile keyfile = new KeyFile(args[1], (ICryptoProvider)provider);
				keyfile.Load();

				NotaryPublic notary = new NotaryPublic(provider);

				if(notary.VerifyBase64(args[3], args[4]))
				{
					Console.WriteLine("VERIFIED: Signatures match.");
				}
				else
				{
					Console.WriteLine("FILED: Signatures do not match.");
				}
			}
			else
			{
				Console.WriteLine("Invalid syntax.");
				Usage();
				return;
			}
		}
	}
}
